package redisenum

import (
	"context"
	"errors"
	"fmt"
	"strconv"
	"time"
	"yunj/pkg/yunj/core/enum"
	"yunj/pkg/yunj/core/redis"
	"yunj/pkg/yunj/util"
)

type KeyInterface interface {
	enum.EnumInterface[string]
	GetArgs() any
	GetStringValue() string
	ByValue(value string) KeyInterface
}

// 实现EnumInerface接口
type Key struct {
	enum.Enum[string]
	KeyInstance KeyInterface // 继承使用
	Args        any
}

// 设置参数
func (rk *Key) SetArgs(args any) *Key {
	rk.Args = args
	return rk
}

// 获取参数
func (rk *Key) GetArgs() any {
	return rk.Args
}

// 获取当前key实例，允许继承设置
func (rk *Key) GetKeyInstance() KeyInterface {
	if rk.KeyInstance != nil {
		return rk.KeyInstance
	}
	return rk
}

// 获取string类型的value
func (rk *Key) GetStringValue() string {
	return string(rk.GetKeyInstance().GetValue())
}

// 获取key
func (rk *Key) GetKey() (string, error) {
	key := rk.GetStringValue()
	keySuffixAttr := rk.GetAttr("keySuffix")
	if keySuffixAttr == nil {
		return key, nil
	}
	keySuffixFunc, ok := KeySubffixCheck(keySuffixAttr)
	if !ok {
		return "", errors.New("keySuffix配置异常")
	}
	keySuffix, err := keySuffixFunc(rk.GetKeyInstance())
	if err != nil {
		return "", err
	}
	key = fmt.Sprintf("%s%s", key, keySuffix)
	return key, nil
}

// 判断是否有key后缀合法的配置定义，如果合法则返回对应的keySuffixFunc和true，否则返回nil和false
func KeySubffixCheck(keySuffix any) (func(KeyInterface) (string, error), bool) {
	keySuffixFunc, ok := keySuffix.(func(KeyInterface) (string, error))
	if !ok {
		return nil, false
	} else {
		return keySuffixFunc, true
	}
}

// 获取缓存结果
// ttl表示过期时间。-1 => 永不过期；0 => 随机1-2天过期（详见SetCache）
// 示例：redisenum.NewKey(redisenum.KeyTEST).SetArgs(map[string]any{"id": 1}).GetCache(600)
func (rk *Key) GetCache(ttl ...int) (res string, err error) {
	key, err := rk.GetKey()
	if err != nil {
		return
	}
	res, _ = redis.Get(context.Background(), key)
	// 判断是否只获取缓存，不设置缓存
	if len(ttl) <= 0 {
		return
	}
	// fmt.Printf("缓存：%v 存在：%v\r\n", key, len(res))
	// 缓存存在，重新设置过期时间后返回
	if len(res) > 0 {
		rk.SetCache(res, ttl[0])
		return
	}
	// 缓存不存在
	valueCall := rk.GetAttr("value")
	// 没有配置原始值获取方式则返回空
	if valueCall == nil {
		return
	}
	// 获取原始值
	valueFunc, ok := valueCall.(func(KeyInterface) (any, error))
	if !ok {
		err = errors.New("原始值获取配置异常！")
		return
	}
	rawValue, err := valueFunc(rk.GetKeyInstance())
	if err != nil {
		return
	}
	// 设置缓存
	rk.SetCache(rawValue, ttl[0])
	// 重新获取缓存
	res, err = redis.Get(context.Background(), key)
	return
}

// 获取缓存结果为int
// 示例：redisenum.NewKey(redisenum.KeyTEST).SetArgs(map[string]any{"id": 1}).GetCacheInt(600)
func (rk *Key) GetCacheInt(ttl int) (int, error) {
	reply, err := rk.GetCache(ttl)
	if err != nil {
		return 0, err
	}
	res, err := strconv.Atoi(string(reply))
	return res, err
}

// 获取缓存结果为int64
// 示例：redisenum.NewKey(redisenum.KeyTEST).SetArgs(map[string]any{"id": 1}).GetCacheInt64(600)
func (rk *Key) GetCacheInt64(ttl int) (int64, error) {
	reply, err := rk.GetCache(ttl)
	if err != nil {
		return 0, err
	}
	res, err := strconv.ParseInt(string(reply), 10, 64)
	return res, err
}

// 获取缓存结果为uint64
// 示例：redisenum.NewKey(redisenum.KeyTEST).SetArgs(map[string]any{"id": 1}).GetCacheUint64(600)
func (rk *Key) GetCacheUint64(ttl ...int) (uint64, error) {
	reply, err := rk.GetCache(ttl...)
	if err != nil {
		return 0, err
	}
	res, err := strconv.ParseUint(string(reply), 10, 64)
	return res, err
}

// 设置缓存
// ttl表示过期时间。-1 => 永不过期；0 => 随机1-2天过期
func (rk *Key) SetCache(value any, ttl int) error {
	var err error
	if ttl < -1 {
		return err
	}
	key, err := rk.GetKey()
	if err != nil {
		return err
	}

	var expire time.Duration
	if ttl == -1 {
		// 永不过期
		expire = 0
	} else {
		if ttl == 0 {
			// 随机1-2天过期
			ttl = util.RandomInt(86400, 172800)
		}
		expire = time.Duration(ttl) * time.Second // 转换为 time.Duration
	}
	// fmt.Printf("设置Redis缓存：key=%v ttl=%v\r\n", ttl, key)
	err = redis.Set(context.Background(), key, value, expire)
	return err
}

// 自增缓存
func (rk *Key) IncrCache() (int64, error) {
	key, err := rk.GetKey()
	if err != nil {
		return 0, err
	}
	res, err := redis.Incr(context.Background(), key)
	return res, err
}

// 删除缓存
// @Param all bool 是否删除所有
func (rk *Key) DelCache(all ...bool) error {
	keys := []string{}
	var err error
	ctx := context.Background()
	// 获取要删除的key
	// 判断是否要删除所有，主要是针对有变量后缀的情况
	if len(all) > 0 && all[0] {
		if keySuffix := rk.GetAttr("keySuffix"); keySuffix != nil {
			if _, ok := keySuffix.(func(*Key) (string, error)); ok {
				// 获取满足条件的所有key
				keys, err = redis.Keys(ctx, rk.GetStringValue())
				if err != nil {
					return err
				}
			}
		}
	}
	if len(keys) <= 0 {
		// 只删除当前key
		key, err := rk.GetKey()
		if err != nil {
			return err
		}
		keys = append(keys, key)
	}
	return redis.Del(ctx, keys)
}

func (rk *Key) ByValue(value string) KeyInterface {
	return KeyByValue(value)
}

// 存储已经创建的实例
var keyInstanceCache = make(map[string]*Key)

// 根据value获取枚举
func KeyByValue(value string) *Key {
	if instance, exists := keyInstanceCache[value]; exists {
		return instance
	}
	e := &Key{}
	enum.SetEnumInstance(&e.Enum, e, value)
	keyInstanceCache[value] = e
	return e
}

var KeyEnum *Key = func() *Key {
	e := &Key{}
	enum.SetEnumInstance(&e.Enum, e)
	return e
}()
